package middlewareWeb;

import java.net.*;
import java.io.*;
import java.util.*;
/**
 * Classe che implementa l'interfaccia AbstractWorker
 * @author myusy
 */

public class Worker implements AbstractWorker, Observer{
    private String id;// Id componente univoco
    private Integer num_sequenza_operazione;//contatore del numero di operazioni
    private Integer num_task_inseriti;//contatore del numero di task inseriti in coda in totale
    private Address workerAddress;
    private WorkerProxyRM proxyRM;
    
     /**
     * Metodo che implementa il metodo update dell'interfaccia Observable
     * 
     */
    @Override
    public void update(Observable queueManager, Object args) {
        System.out.println("****************************************** STO OSSERVANDO");
        Thread server_esegui = new Thread(new WorkerThreadEsegui(this,(TQueueManager)queueManager));
        server_esegui.start();
	}

    /**
     * Metodo costruttore dell'oggetto Worker
     */
    public Worker(){
        this.num_sequenza_operazione = 0;
        this.num_task_inseriti = 0;
        this.proxyRM = new WorkerProxyRM();
        initClocks();
    }
    /**
     * Metodo costruttore dell'oggetto Worker
     */
    public Worker(String id, Integer seq, Integer task, Address add){
        this.id = id;
        this.num_sequenza_operazione = seq;
        this.num_task_inseriti = task;
        this.workerAddress = add;
        this.proxyRM = new WorkerProxyRM();
        initClocks();
    }
    /**
     * Metodo costruttore dell'oggetto Worker
     */
    public Worker(int port, String ip, String id){
        workerAddress = new Address(port,ip);
        this.id = id;
        this.num_sequenza_operazione = 0;
        this.num_task_inseriti = 0;
        this.proxyRM = new WorkerProxyRM();
        initClocks();
    }

    
    /**
     * metodo che inizializza il vector clock locale del manager
     */
    private void initClocks()
    {
        this.proxyRM.getClocks().put("M001",new Integer(0));
        this.proxyRM.getClocks().put("W001",new Integer(0));
        this.proxyRM.getClocks().put("W002",new Integer(0));
        this.proxyRM.getClocks().put("W003",new Integer(0));
        this.proxyRM.getClocks().put("T001",new Integer(0));
        this.proxyRM.getClocks().put("F001",new Integer(0));
    }

    /**
     * metodo che restituisce l'oggetto di tipo WorkerProxyRM
     * @return
     */
    public WorkerProxyRM getProwyRM(){
        return this.proxyRM;
    }

    /**
     * Metodo che restituisce l'identificativo
     * @return ID univoco del Worker
     */
    public String getId(){
        return this.id;

    }
    /**
     * Metodo che restituisce il timestamp()
     * @return una stringa che racchiude il contenuto del vector clock
     */
    public String getTimestamp()
    {
        return this.proxyRM.getClocks().toString();
    }
    
    
    /**
     * Metodo che restituisce il numero di sequenza operazione
     * @return numero di operazioni finora effettuate dal componente
     */
    public Integer getSequenzaOperazione(){
          return this.num_sequenza_operazione;

    }
    /**
     * Metodo che implementa il contatore delle operazioni effettuate
     * @return numero di operazioni finora effettuate dal componen
     */
    public Integer IncrementaSequenzaOperazione(){
        this.num_sequenza_operazione ++;
        return this.num_sequenza_operazione;
    }
    /**
     * Metodo che incrementa il valore del contatore che conta il numero di task inseriti
     * @return numero di task inseriti in coda
     */
    public Integer IncrementaTaskInseriti(){
        this.num_task_inseriti ++;
        return this.num_task_inseriti;
    }
    /**
     * Metodo che restituisce il numero task inseriti in coda
     * @return numero di task inseriti in coda
     */
    public Integer getTaskInseriti(){
        return this.num_task_inseriti;
    }
    /**
     * Metodo che incrementa il valore del clock del componente
     * @return una stringa che racchiude il contenuto del vector clock
     */
    public String IncrementaClock(){
        int a= ((Integer)this.proxyRM.getClocks().get(this.id)).intValue();
        a++;
        this.proxyRM.getClocks().put(this.id,new  Integer(a));
        return this.proxyRM.getClocks().toString();
    }

    /**
     * Metodo che restituisce l'indirizzo del Worker
     * @return oggetto di tipo Address
     */
    public Address getWorkerAddress(){
        return this.workerAddress;
    }
    /**
     * Implementazione del metodo di interfaccia del worker per eseguire il task
     * @param td Descrittore del task da eseguire
     * @return un intero che indica il risultato dell'esecuzione
     */
    public int exec (TaskDescriptor td){
        System.out.println("DENTRO EXEC");
        if(td.getType() == TaskTYPE.Executable)
            System.out.println("Task Eseguibile");
        else if(td.getType() == TaskTYPE.Literals)
                System.out.println("Task Letterale");
        else System.out.println("Task scriptBash");
        try{
            ProcessBuilder proc = new ProcessBuilder(td.getCommand(), td.getLink());
            proc.start();
        }catch(IOException e){
            //e.printStackTrace();
            System.out.println("Comando: "+ td.getCommand());
            System.out.println("Link: "+ td.getLink());
        }

        return 0;//comando momentaneo d'appoggio

    }



    public void run()
    {
        TQueueManager queueManager = new TQueueManager();
        queueManager.setAddr(getWorkerAddress());

        /* Scrittura Log */
        LoggerMW logger= new LoggerMW();
        logger.creaLog(getId(),IncrementaClock(),IncrementaSequenzaOperazione().toString(),queueManager.getTQueue().size(),getTaskInseriti().toString(),queueManager.toXML(),"Avvio Worker");
        
        queueManager.addObserver(this);

        System.out.println("QueueManager Worker avviato");
        try{

            DatagramSocket socketSrv = new DatagramSocket(getWorkerAddress().getPort());
            System.out.println("Server Worker avviato");
            while(true){
                byte[] buffer = new byte[512];
                DatagramPacket packetIn = new DatagramPacket(buffer,buffer.length);
                socketSrv.receive(packetIn);

                System.out.println("Arrivato pacchetto UDP al worker");
                Thread server_ascolta = new Thread(new WorkerThread(this,queueManager,socketSrv,packetIn,buffer));
                server_ascolta.start();
            }
        }
        catch(Exception e)
        {
            System.out.println("Eccezione: " + e.getMessage());
        }



           /// System.out.println(t_server.getId());
    }

    public static void main(String[] args) throws SocketException{

        Worker worker = new Worker(5000,"127.0.0.1","W001");
        System.out.println("Worker " + worker.id +" avviato");
	worker.run();

    }
}

